package model.arbolBSharp;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;

import model.archivo.ArchivoBloques;

public class ManipuladorNodos {
	
	private ArchivoBloques archivo;
	private ConversorBytesNodo empNodo = new ConversorBytesNodo();
	private ConversorBytesHoja empHoja = new ConversorBytesHoja();
	
	public ManipuladorNodos (ArchivoBloques archivo){
		if(archivo==null)
			throw new NullPointerException("archivo");
		this.archivo = archivo;		
	}
	
	/**
	 * Guarda el nodo en el archivo.
	 * 
	 * @param nodo
	 * @return true si se logra guardar en el archivo. false si el nodo estaba en overflow.
	 * @throws ArbolBSharpException
	 */
	public boolean guardar(Nodo nodo) throws ArbolBSharpException{
		if(nodo==null)
			throw new NullPointerException("nodo");
		
		if(nodo.getPosicionEnArchivo()==null)
			throw new ArbolBSharpException("El nodo debe tener definida la posicion donde se debe guardar");
		
		ByteArrayOutputStream arrayBytes = new ByteArrayOutputStream();
		try {
			empNodo.setNodo(nodo);
			empNodo.convertirABytes(arrayBytes);
			if (arrayBytes.toByteArray().length > archivo.GetTamanioBloque())
				return false;
			archivo.EscribirBloque(arrayBytes.toByteArray(), nodo.getPosicionEnArchivo());
		} catch (IOException e) {
			throw new ArbolBSharpException("Error al guardar el nodo", e);
		}
		return true;
	}
	
	public boolean guardarRaiz(Nodo nodo) throws ArbolBSharpException{
		if(nodo==null)
			throw new NullPointerException("nodo");
		
		if(nodo.getPosicionEnArchivo()==null)
			throw new ArbolBSharpException("El nodo debe tener definida la posicion donde se debe guardar");
		
		ByteArrayOutputStream arrayBytes = new ByteArrayOutputStream();
		try {
			empNodo.setNodo(nodo);
			empNodo.convertirABytes(arrayBytes);
			if (arrayBytes.toByteArray().length > archivo.GetTamanioBloque()*2)
				return false;
			archivo.EscribirBloque(arrayBytes.toByteArray(), nodo.getPosicionEnArchivo());
		} catch (IOException e) {
			throw new ArbolBSharpException("Error al guardar el nodo", e);
		}
		return true;
	}
	
	
	/**
	 * Guarda la hoja en el archivo
	 * 
	 * @param hoja
	 * @return true si logra guardar el nodo en el archivo. false si el nodo estaba en overflow
	 * @throws ArbolBSharpException
	 */
	public boolean guardar(Hoja hoja) throws ArbolBSharpException{
		if(hoja==null)
			throw new NullPointerException("hoja");		
		
		if(hoja.getPosicionEnArchivo()==null)
			throw new ArbolBSharpException("La hoja debe tener definida la posicion donde se debe guardar");
		
		ByteArrayOutputStream arrayBytes = new ByteArrayOutputStream();
		try {
			empHoja.setHoja(hoja);
			empHoja.convertirABytes(arrayBytes);
			if (arrayBytes.toByteArray().length > archivo.GetTamanioBloque())
				return false;
			archivo.EscribirBloque(arrayBytes.toByteArray(), hoja.getPosicionEnArchivo());
		} catch (IOException e) {
			throw new ArbolBSharpException("Error al guardar el nodo", e);
		}
		return true;
	}
	
	public boolean guardarRaiz(Hoja hoja) throws ArbolBSharpException{
		if(hoja==null)
			throw new NullPointerException("hoja");		
		
		if(hoja.getPosicionEnArchivo()==null)
			throw new ArbolBSharpException("La hoja debe tener definida la posicion donde se debe guardar");
		
		ByteArrayOutputStream arrayBytes = new ByteArrayOutputStream();
		try {
			empHoja.setHoja(hoja);
			empHoja.convertirABytes(arrayBytes);
			if (arrayBytes.toByteArray().length > archivo.GetTamanioBloque()*2)
				return false;
			archivo.EscribirBloque(arrayBytes.toByteArray(), hoja.getPosicionEnArchivo());
		} catch (IOException e) {
			throw new ArbolBSharpException("Error al guardar el nodo", e);
		}
		return true;
	}

	public Nodo leerNodo(int posicion) throws ArbolBSharpException{
		if(posicion<0)
			throw new ArbolBSharpException("La posicion no puede ser negativa");
		
		byte[] arrayBytes = new byte[archivo.GetTamanioBloque()];
		
		try {
			archivo.LeerBloque(arrayBytes, posicion);
			empNodo.convertirAObjetos(new ByteArrayInputStream(arrayBytes));
			return empNodo.getNodo();
			
		} catch (IOException e) {
			throw new ArbolBSharpException("No se puede leer el nodo del archivo", e);
		}
	}
	
	public Nodo leerNodoRaiz(int posicion) throws ArbolBSharpException{
		if(posicion<0)
			throw new ArbolBSharpException("La posicion no puede ser negativa");
		
		byte[] arrayBytes = new byte[2*archivo.GetTamanioBloque()];
		
		try {
			archivo.LeerBloque(arrayBytes, posicion);
			empNodo.convertirAObjetos(new ByteArrayInputStream(arrayBytes));
			return empNodo.getNodo();
			
		} catch (IOException e) {
			throw new ArbolBSharpException("No se puede leer el nodo del archivo", e);
		}
	}
	
	public Hoja leerHoja(int posicion) throws ArbolBSharpException{
		if(posicion<0)
			throw new ArbolBSharpException("La posicion no puede ser negativa");
		
		byte[] arrayBytes = new byte[archivo.GetTamanioBloque()];
		
		try {
			archivo.LeerBloque(arrayBytes, posicion);
			empHoja.convertirAObjetos(new ByteArrayInputStream(arrayBytes));
			return empHoja.getHoja();
			
		} catch (IOException e) {
			throw new ArbolBSharpException("No se puede leer el nodo del archivo", e);
		}
	}
	
	public Hoja leerHojaRaiz(int posicion) throws ArbolBSharpException{
		if(posicion<0)
			throw new ArbolBSharpException("La posicion no puede ser negativa");
		
		byte[] arrayBytes = new byte[archivo.GetTamanioBloque()*2];
		
		try {
			archivo.LeerBloque(arrayBytes, posicion);
			empHoja.convertirAObjetos(new ByteArrayInputStream(arrayBytes));
			return empHoja.getHoja();
			
		} catch (IOException e) {
			throw new ArbolBSharpException("No se puede leer el nodo del archivo", e);
		}
	}
	
	public int getBloqueLibre() throws ArbolBSharpException{
		try {
			return (int)archivo.GetCantidadBloques();
		} catch (IOException e) {
			throw new ArbolBSharpException("Error al obtener el tama?o del archivo", e);
		}
	}

	public void flush() {
		// TODO Auto-generated method stub
		
	}

	public long getCatidadNodos() throws ArbolBSharpException {
		try {
			return archivo.GetCantidadBloques();
		} catch (IOException e) {
			throw new ArbolBSharpException("Error al tratar de obtener la cantidad de bloques del archivo", e);
		}
	}

	public void cerrar() throws ArbolBSharpException {
		try {
			archivo.cerrarArchivo();
		} catch (IOException e) {
			throw new ArbolBSharpException("Error al cerrar el archivo en bloques", e);
		}		
	}

}
